#ifndef __WARPUTIL_H
#define __WAPUTIL_H
#include <string>
#include <vector>
#include <deque>
using std::string;
using std::vector;
using std::deque;

class warpSol;

/** We have implemented two variants utilizing  SMP machines for multi-processing, one
 * is based on the pthread library, one using fork. The fork variant may (or may not) be easier to port to other 
 * OS's [windows], but none of the two has currently been tested on windows. Don't enable
 * both simultaneously
 **/ 
#define  HAVE_THREADS
#undef USE_FORK

/**********************************************************************/
/* A helper class which is used to encapsule routines to traverse     */
/* directory tress. It also contains a simple API for (un)compression */
/**********************************************************************/

class warputil {
public:
  warputil();
  ~warputil();

  /* Overwrite files ? */
  bool coward() { return _coward; }
  bool coward(bool c) { return _coward = c; }


  /* Overwrite files ? */
  bool continuation()       { return _continuation; }
  bool continuation(bool c) { return _continuation = c; }

  /* Continue if individual files can not be processed */
  bool robust() { return _robust; }
  bool robust(bool c) { return _robust = c; }

  /* Preserve permissions and access times ? */
  bool preserveAP() { return _preserve; }
  bool preserveAP(bool c) { return _preserve = c; }
  
  /* Compression target rate */
  string &rate()  { return _rate; } 
  string &rate(string r)  { return _rate = r; } 
  

  /* Compression target rate */
  string &tilesize()  { return _tile; } 
  string &tilesize(string r)  { return _tile = r; } 
  
 
  /* Entry point to (un) compress a single file */
  int unCompressFile(string infile, string outfile, warpSol &);
  int compressFile(string infile, string outfile, warpSol &);

  /* (Un)compress a directory recursively */
  int processDirs(string sdir, string tdir, bool compress);

 private:
  friend void *slaveEntryPoint(void *);
  bool _coward, _preserve, _robust, _continuation;
  string _rate, _tile;

  int _crawl(string sdir, string tdir, bool compress);


  class _task {
  public:
    _task(const string &in, const string &out, bool cmprs) : _in(in), _out(out), _cmprs(cmprs) {}
    const string &in()  const { return _in; }
    const string &out() const { return _out; }
    bool compress()     const { return _cmprs; }
  private:
    string _in, _out;
    bool _cmprs;
  };

  deque<_task> _pipeline;
  void _schedule(const string &in, const string &out, bool mode);

#ifndef HAVE_THREADS
  int _executePipeline(int start, int end);
#else
  void _asyncStart();
  void _asyncEnd();
  void _aSlavesLife();

  vector<pthread_t> _slaves;

  bool _cancel, _finalize;
  int _errorcode;

  pthread_mutex_t _mutex;
  pthread_cond_t  _slave, _master;
#endif //HAVE_THREADS


#if defined HAVE_THREADS || defined USE_FORK
 public: 
  int nProcessor() { return _nproc; }
  int nProcessor(int n) { return _nproc = n; }
 private:
  int _nproc;
#endif // HAVE_THREADS || USE_FORK

};

#if defined HAVE_THREADS && defined USE_FORK
#error Please select only one, HAVE_THREADS or USE_FORK, but not both
#endif
 
#endif

